/*
 * AD9954 IO Driver source file
 */

#include <LPC11xx.h>
#include <stdbool.h>

#include "gpio.h"
#include "SSP.h"
#include "hw_ad9954.h"


extern void delayus(uint32_t us);

void ad9954_io_init(void)
{
	SSPInit(AD9954_SPI_PORT, SSP_ClockPolarity_Low, SSP_ClockPhase_RisingEdge);

	GPIOSetDir(AD9954_CTL_PORT_AND_POS_RST, GPIO_DIR_OUTPUT);
	GPIOSetDir(AD9954_CTL_PORT_AND_POS_UPDATE, GPIO_DIR_OUTPUT);
	GPIOSetDir(AD9954_CTL_PORT_AND_POS_PWRDWN, GPIO_DIR_OUTPUT);
	GPIOSetDir(AD9954_CTL_PORT_AND_POS_IOSYNC, GPIO_DIR_OUTPUT);
	GPIOSetDir(AD9954_CTL_PORT_AND_POS_OSK, GPIO_DIR_OUTPUT);
	GPIOSetDir(AD9954_CTL_PORT_AND_POS_PS0, GPIO_DIR_OUTPUT);
	GPIOSetDir(AD9954_CTL_PORT_AND_POS_PS1, GPIO_DIR_OUTPUT);

//	GPIOSetPullup (&AD9954_CTL_RST_IOCON, GPIO_Pullup_Mode_Inactive);
//	GPIOSetPullup (&AD9954_CTL_UPDATE_IOCON, GPIO_Pullup_Mode_Inactive);
//	GPIOSetPullup (&AD9954_CTL_PWRDWN_IOCON, GPIO_Pullup_Mode_Inactive);
//	GPIOSetPullup (&AD9954_CTL_IOSYNC_IOCON, GPIO_Pullup_Mode_Inactive);
//	GPIOSetPullup (&AD9954_CTL_OSK_IOCON, GPIO_Pullup_Mode_Inactive);
//	GPIOSetPullup (&AD9954_CTL_PS0_IOCON, GPIO_Pullup_Mode_Inactive);
//	GPIOSetPullup (&AD9954_CTL_PS1_IOCON, GPIO_Pullup_Mode_Inactive);

	GPIOSetValue(AD9954_CTL_PORT_AND_POS_RST, 0);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_UPDATE, 0);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_PWRDWN, 0);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_IOSYNC, 0);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_OSK, 0);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_PS0, 0);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_PS1, 0);

	SSPDeselect(AD9954_SPI_PORT);
}

void ad9954_hwrst(void)
{
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_RST, 1);
	delayus(200);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_RST, 0);
}

void ad9954_update(void)
{
	while(SSPBusy(AD9954_SPI_PORT));
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_UPDATE, 1);
	//delayus(200);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_UPDATE, 0);
}

void ad9954_iosync(void)
{
	while(SSPBusy(AD9954_SPI_PORT));
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_IOSYNC, 1);
	delayus(200);
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_IOSYNC, 0);
}

void ad9954_pwrdwn_set(bool set)
{
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_PWRDWN, set ? 1:0);
}

void ad9954_osk_set(bool set)
{
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_OSK, set ? 1:0);
}

void ad9954_ps0_set(bool set)
{
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_PS0, set ? 1:0);
}

void ad9954_ps1_set(bool set)
{
	GPIOSetValue(AD9954_CTL_PORT_AND_POS_PS1, set ? 1:0);
}


void ad9954_register_write(enum AD9954_Register reg, uint8_t *data)
{
    uint32_t len = sizeofRegister[reg];
    
    // do IO_SYNC before a operation to clear the influence of operations before this.
    ad9954_iosync();
    
	SSPSelect(AD9954_SPI_PORT);
	SSPSendByte(AD9954_SPI_PORT, reg);
	SSPSend(AD9954_SPI_PORT, data, len);
	SSPDeselect(AD9954_SPI_PORT);
}

void ad9954_register_read(enum AD9954_Register reg, uint8_t *data)
{
    uint32_t len = sizeofRegister[reg];
    
	SSPSelect(AD9954_SPI_PORT);
	SSPSendByte(AD9954_SPI_PORT, reg|0x80);
	SSPReceive(AD9954_SPI_PORT, data, len);
	SSPDeselect(AD9954_SPI_PORT);
}

void ad9954_ram_write(uint32_t *data, uint32_t len)
{
	uint8_t cache[4];
    uint32_t i;
    
	SSPSelect(AD9954_SPI_PORT);
	SSPSendByte(AD9954_SPI_PORT, AD9954_RAM);
    
    for (i = 0; i < len; ++i) {
    	cache[0]=(data[i]>>24)&0xff;
    	cache[1]=(data[i]>>16)&0xff;
    	cache[2]=(data[i]>>8)&0xff;
    	cache[3]=data[i]&0xff;
	    SSPSend(AD9954_SPI_PORT, cache, 4);
    }
    
	SSPDeselect(AD9954_SPI_PORT);
}

void ad9954_ram_read(uint32_t *data, uint32_t len)
{
	uint8_t cache[4];
    uint32_t i;
    
	SSPSelect(AD9954_SPI_PORT);
	SSPSendByte(AD9954_SPI_PORT, AD9954_RAM|0x80);
    
    for (i = 0; i < len; ++i) {
    	cache[0]=(data[i]>>24)&0xff;
    	cache[1]=(data[i]>>16)&0xff;
    	cache[2]=(data[i]>>8)&0xff;
    	cache[3]=data[i]&0xff;
	    SSPReceive(AD9954_SPI_PORT, cache, 4);
    }
    
	SSPDeselect(AD9954_SPI_PORT);
}
